# -*- coding: utf-8 -*-
import KBEngine
import IKernel
import MsgDef
import RoomDef
import ErrorCodeDef
import ConstDef
import StateDef
import CardDef
import time
import random
import copy


class RoomModule:
	def __init__(self):
		pass

	def init(self, isReload):
		IKernel.Instance().registerFunc("RoomModule.onRoomInit", self.onRoomInit)
		IKernel.Instance().registerFunc("RoomModule.onTeleportSuccess", self.onTeleportSuccess)
		IKernel.Instance().registerFunc("RoomModule.onClientMsg", self.onClientMsg)
		IKernel.Instance().registerFunc("RoomModule.onHandCardsChanged", self.onHandCardsChanged)
		IKernel.Instance().registerFunc("RoomModule.onPlayerCurStateChanged", self.onPlayerCurStateChanged)
		IKernel.Instance().registerFunc("RoomModule.HB_jiaoDizhuTimeout", self.HB_jiaoDizhuTimeout)
		IKernel.Instance().registerFunc("RoomModule.HB_qiangDizhuTimeout", self.HB_qiangDizhuTimeout)
		IKernel.Instance().registerFunc("RoomModule.HB_playoutTimeout", self.HB_playoutTimeout)

		IKernel.Instance().addEventCallback("Room", "init", "RoomModule.onRoomInit")
		IKernel.Instance().addEventCallback("Account", "onTeleportSuccess", "RoomModule.onTeleportSuccess")
		IKernel.Instance().addIntMsgCallback(MsgDef.CLIENT2CELL_ROOM_MSG, "RoomModule.onClientMsg")

	def end(self):
		pass

	def onRoomInit(self, eventType, eventName, senderEntityID, receiverEntityID, args):
		roomEntity = KBEngine.entities.get(receiverEntityID)
		for i in range(0, RoomDef.OneRoomMaxPlayerNum):
			roomEntity.allPlayers[i] = 0

	def onHandCardsChanged(self, entityID, propName, oldValue):
		entity = KBEngine.entities.get(entityID)
		entity.handCardNum = len(entity.handCards)

	def onPlayerCurStateChanged(self, entityID, propName, oldValue):
		playerEntity = KBEngine.entities.get(entityID)
		if playerEntity.curState == StateDef.Player.JiaoDizhu:
			self.addHeartbeat(playerEntity.id, "RoomModule.HB_jiaoDizhuTimeout")
		elif playerEntity.curState == StateDef.Player.QiangDizhu:
			self.addHeartbeat(playerEntity.id, "RoomModule.HB_qiangDizhuTimeout")
		elif playerEntity.curState == StateDef.Player.FirstPlayout or playerEntity.curState == StateDef.Player.FollowPlayout:
			self.addHeartbeat(playerEntity.id, "RoomModule.HB_playoutTimeout")
		elif playerEntity.curState == StateDef.Player.Win:
			self.handWin(playerEntity.roomEntityID)

	def isFull(self, roomEntity):
		playerNum = 0
		for i in range(len(roomEntity.allPlayers)):
			if roomEntity.allPlayers[i] != 0:
				playerNum = playerNum + 1

		return (playerNum >= RoomDef.OneRoomMaxPlayerNum)

	def onTeleportSuccess(self, eventType, eventName, senderEntityID, receiverEntityID, args):
		roomEntity = KBEngine.entities.get(senderEntityID)
		if roomEntity.getScriptName() != "Room":
			return

		playerEntityID = receiverEntityID

		playerEntity = KBEngine.entities.get(playerEntityID)
		playerEntity.setViewRadius(playerEntity.orgViewRadius,5)
		playerEntity.position.x = 0
		playerEntity.position.y = 0
		playerEntity.position.z = 0
		playerEntity.roomEntityID = roomEntity.id
		playerEntity.roomID = roomEntity.roomID

		for i in range(0, RoomDef.OneRoomMaxPlayerNum):
			if roomEntity.allPlayers[i] == 0:
				roomEntity.allPlayers[i] = playerEntityID
				playerEntity.seatPos = i + 1
				break

	def giveCard(self, roomEntity):
		"""
		发牌
		"""
		allCards = copy.deepcopy(CardDef.allCards)

		willPlayCards = []
		while len(allCards) > 0:
			randIndex = random.randint(0, len(allCards) - 1)
			card = allCards.pop(randIndex)
			willPlayCards.append(card)

		roomEntity.curOpCardPlayerPos = random.randint(0, RoomDef.OneRoomMaxPlayerNum - 1)
		roomEntity.firstOpCardPlayerPos = roomEntity.curOpCardPlayerPos
		roomEntity.curState = StateDef.Player.JiaoDizhu

		curPlayPos = 0
		while len(willPlayCards) > 0:
			if len(willPlayCards) > CardDef.DipaiNum:
				playerEntityID = roomEntity.allPlayers[curPlayPos]
				playerEntity = KBEngine.entities.get(playerEntityID)
				playerEntity.handCards[willPlayCards.pop(0)] = 1
				if playerEntity.curState != StateDef.Player.WaitJiaoDizhu \
					and playerEntity.curState != StateDef.Player.JiaoDizhu :
					if curPlayPos == roomEntity.curOpCardPlayerPos:
						playerEntity.curState = StateDef.Player.JiaoDizhu
					else:
						playerEntity.curState = StateDef.Player.WaitJiaoDizhu

				curPlayPos = (curPlayPos + 1) % RoomDef.OneRoomMaxPlayerNum
			else:
				roomEntity.dipai[willPlayCards.pop(0)] = 1

		for i in range(0, RoomDef.OneRoomMaxPlayerNum):
			playerEntityID = roomEntity.allPlayers[i]
			# 添加手牌变化回调
			IKernel.Instance().addPropChangedCallback(playerEntityID, "handCards", "RoomModule.onHandCardsChanged")
			self.onHandCardsChanged(playerEntityID, "handCards", {})
			# 添加玩家状态变化回调
			IKernel.Instance().addPropChangedCallback(playerEntityID, "curState", "RoomModule.onPlayerCurStateChanged")
			self.onPlayerCurStateChanged(playerEntityID, "curState", 0)

	def addHeartbeat(self, playerID, funcName,
		count = 1,
		defaultTime = ConstDef.DEFAULT_OP_TIMEOUT,
		minTime = ConstDef.ROBOT_THINK_MIN_TIME,
		maxTime = ConstDef.ROBOT_THINK_MAX_TIME
		) :
		timeout = defaultTime * 1000
		curOpCardPlayer = KBEngine.entities.get(playerID)
		if curOpCardPlayer.playerType == RoomDef.PlayerType.Robot:
			# 如果是电脑人则模拟思考1到3秒
			timeout = rand.randint(minTime, maxTime) * 1000
		IKernel.Instance().addHeartbeat(playerID, funcName, timeout, count)

	def onClientMsg(self, senderEntityID, receiverEntityID, args):
		playerEntityID = receiverEntityID
		playerEntity = KBEngine.entities.get(playerEntityID)

		roomEntity = KBEngine.entities.get(playerEntity.roomEntityID)
		if roomEntity.getScriptName() != "Room" \
			or playerEntity.curState < StateDef.Player.RoomNoPlayWait:
			# 玩家不再房间中
			return

		dispatcher = {
			RoomDef.SUBMSG_PREPARE : self.playerPrepare,
			RoomDef.SUBMSG_CANCEL_PREPARE : self.playerCancelPrepare,
			RoomDef.SUBMSG_QIANG_DIZHU : self.playerQiangDizhu,
			RoomDef.SUBMSG_PALYOUT_CARD : self.playoutCard,
			RoomDef.SUBMSG_JIAODIZHU : self.jiaodizhu,
		}
		submsg = args[1]
		funcAddr = dispatcher.get(submsg)
		if funcAddr == None:
			return
		funcAddr(receiverEntityID, args)

	def getNextOpPlayerEntityIDAndPos(self, playerEntityID):
		playerEntity = KBEngine.entities.get(playerEntityID)
		roomEntity  = KBEngine.entities.get(playerEntity.roomEntityID)

		for i in range(0, RoomDef.OneRoomMaxPlayerNum):
			loopPlayerEntity = KBEngine.entities.get(roomEntity.allPlayers[i])
			if playerEntity.id != loopPlayerEntity.id:
				continue

			nextPos = i + 1
			if nextPos >= RoomDef.OneRoomMaxPlayerNum:
				nextPos = 0

			return [roomEntity.allPlayers.get(nextPos), nextPos]

		# 这里出错了
		assert(False)
		return -1

	def isCurPlayerOp(self, playerEntityID):
		playerEntity = KBEngine.entities.get(playerEntityID)
		roomEntity  = KBEngine.entities.get(playerEntity.roomEntityID)
		curOpPlayerEntityID = roomEntity.allPlayers.get(roomEntity.curOpCardPlayerPos)
		if curOpPlayerEntityID != playerEntity.id:
			return False
		return True

	def playerPrepare(self, receiverEntityID, args):
		playerEntity = KBEngine.entities.get(receiverEntityID)
		if playerEntity.curState >= StateDef.Player.RoomPrepare:
			return

		playerEntity.curState = StateDef.Player.RoomPrepare

		msg = []
		msg.append(MsgDef.CELL2CLIENT_ROOM_MSG)
		msg.append(RoomDef.SUBMSG_PREPARE)
		msg.append(ErrorCodeDef.No)
		IKernel.Instance().sendClientMsg(receiverEntityID, msg)

		preparePlayerNum = 0
		roomEntity = KBEngine.entities.get(playerEntity.roomEntityID)
		for seatPos, playerEntityID in roomEntity.allPlayers.items():
			playerEntity = KBEngine.entities.get(playerEntityID)
			if playerEntity == None:
				return

			if playerEntity.curState == StateDef.Player.RoomPrepare:
				preparePlayerNum += 1

		# 玩家没有全部准备，或者人数不够
		if preparePlayerNum < RoomDef.OneRoomMaxPlayerNum:
			return
		self.giveCard(roomEntity)

	def playerCancelPrepare(self, playerEntityID, args):
		playerEntity = KBEngine.entities.get(playerEntityID)
		if playerEntity.curState > StateDef.Player.RoomPrepare:
			return

		playerEntity.curState = StateDef.Player.RoomNoPlayWait

		msg = []
		msg.append(MsgDef.CELL2CLIENT_ROOM_MSG)
		msg.append(RoomDef.SUBMSG_CANCEL_PREPARE)
		msg.append(ErrorCodeDef.No)
		IKernel.Instance().sendClientMsg(receiverEntityID, msg)
		
	def HB_jiaoDizhuTimeout(self, playerEntityID, curCount, interval):
		args = []
		args.append(MsgDef.CLIENT2CELL_ROOM_MSG)
		args.append(RoomDef.SUBMSG_JIAODIZHU)
		args.append(0)
		self.jiaodizhu(playerEntityID, args)

	def jiaodizhu(self, receiverEntityID, args):
		playerEntity = KBEngine.entities.get(receiverEntityID)
		if playerEntity.curState != StateDef.Player.JiaoDizhu or self.isCurPlayerOp(playerEntity.id) == False:
			return

		IKernel.Instance().delHeartbeat(playerEntity.id, "RoomModule.HB_jiaoDizhuTimeout")

		PlayerEntityIDAndPos = self.getNextOpPlayerEntityIDAndPos(playerEntity.id)
		nextPlayerEntityID = PlayerEntityIDAndPos[0]
		nextPlayerPos = PlayerEntityIDAndPos[1]

		roomEntity = KBEngine.entities.get(playerEntity.roomEntityID)
		isJiaodizhu = args[2]
		for i in range(0, RoomDef.OneRoomMaxPlayerNum):
			loopPlayerEntity = KBEngine.entities.get(roomEntity.allPlayers[i])
			if isJiaodizhu == 1:
				if loopPlayerEntity.id == playerEntity.id:
					# 叫地主=1 抢地主+2
					loopPlayerEntity.qiangDizhuCount = 1
				loopPlayerEntity.curState = StateDef.Player.WaitQiangDizhu
			else:
				if loopPlayerEntity.id == playerEntity.id:
					loopPlayerEntity.curState = StateDef.Player.WaitJiaoDizhu
					firstOpPlayerEntityID = roomEntity.allPlayers.get(roomEntity.firstOpCardPlayerPos)
					# 一圈都没有叫地主，这把牌黄了，重新来一次
					if firstOpPlayerEntityID == nextPlayerEntityID :
						self.giveCard(roomEntity)
						return

					break;

		nextPlayerEntity = KBEngine.entities.get(nextPlayerEntityID)
		if isJiaodizhu == 1:
			nextPlayerEntity.curState = StateDef.Player.QiangDizhu
		else:
			nextPlayerEntity.curState = StateDef.Player.JiaoDizhu

		roomEntity.firstOpCardPlayerPos = nextPlayerPos
		roomEntity.curOpCardPlayerPos = nextPlayerPos

		msg = []
		msg.append(MsgDef.CELL2CLIENT_ROOM_MSG)
		msg.append(RoomDef.SUBMSG_JIAODIZHU)
		msg.append(ErrorCodeDef.No)
		IKernel.Instance().sendClientMsg(receiverEntityID, msg)

	def HB_qiangDizhuTimeout(self, playerEntityID, curCount, interval):
		args = []
		args.append(MsgDef.CLIENT2CELL_ROOM_MSG)
		args.append(RoomDef.SUBMSG_QIANG_DIZHU)
		args.append(0)
		self.playerQiangDizhu(playerEntityID, args)

	def playerQiangDizhu(self, playerEntityID, args):
		playerEntity = KBEngine.entities.get(playerEntityID)
		if playerEntity.curState != StateDef.Player.QiangDizhu or self.isCurPlayerOp(playerEntity.id) == False:
			return

		IKernel.Instance().delHeartbeat(playerEntity.id, "RoomModule.HB_qiangDizhuTimeout")

		roomEntity = KBEngine.entities.get(playerEntity.roomEntityID)

		isAgree = args[2]
		if isAgree == 1:
			# 叫地主=1 抢地主+2
			playerEntity.qiangDizhuCount += 2
			playerEntity.curState = StateDef.Player.AgreeQiangDizhu
			qiangDizhuCount = 0
			for i in range(0, RoomDef.OneRoomMaxPlayerNum):
				loopPlayerEntity = KBEngine.entities.get(roomEntity.allPlayers[i])
				if loopPlayerEntity.curState == StateDef.Player.AgreeQiangDizhu \
					or loopPlayerEntity.curState == StateDef.Player.RefuseQiangDiZhu :
					qiangDizhuCount = qiangDizhuCount + 1

			if qiangDizhuCount == RoomDef.OneRoomMaxPlayerNum:
				self.assignDizhu(roomEntity)
				return
		else:
			playerEntity.curState = StateDef.Player.RefuseQiangDiZhu

		PlayerEntityIDAndPos = self.getNextOpPlayerEntityIDAndPos(playerEntity.id)
		nextPlayerEntityID = PlayerEntityIDAndPos[0]
		nextPlayerPos = PlayerEntityIDAndPos[1]
		nextPlayerEntity = KBEngine.entities.get(nextPlayerEntityID)
		nextPlayerEntity.curState = StateDef.Player.QiangDizhu
		roomEntity.curOpCardPlayerPos = nextPlayerPos

		msg = []
		msg.append(MsgDef.CELL2CLIENT_ROOM_MSG)
		msg.append(RoomDef.SUBMSG_QIANG_DIZHU)
		msg.append(ErrorCodeDef.No)
		IKernel.Instance().sendClientMsg(playerEntity.id, msg)

	def assignDizhu(self, roomEntity):
		# 最终地主实体
		dizhuEntity = None
		for i in range(0, RoomDef.OneRoomMaxPlayerNum):
			playerEntityID = roomEntity.allPlayers[i]
			playerEntity = KBEngine.entities.get(playerEntityID)
			if dizhuEntity == None \
				or playerEntity.qiangDizhuCount > dizhuEntity.qiangDizhuCount:
				# 地主实体
				dizhuEntity = playerEntity
				# 当前操作牌的玩家索引，也就是地主的索引
				roomEntity.curOpCardPlayerPos = i
				roomEntity.firstOpCardPlayerPos = i

		# 给地主底牌
		dizhuEntity.handCards.update(roomEntity.dipai)

		dizhuEntity.isDizhu = 1
		# 把底牌赋值到明牌上，让所有人看到底牌内容
		roomEntity.dipaiMingPai = roomEntity.dipai

		for i in range(0, RoomDef.OneRoomMaxPlayerNum):
			playerEntityID = roomEntity.allPlayers[i]
			playerEntity = KBEngine.entities.get(playerEntityID)
			if dizhuEntity.id == playerEntity.id:
				playerEntity.curState = StateDef.Player.FirstPlayout
			else:
				playerEntity.curState = StateDef.Player.WaitPlayout

	def HB_playoutTimeout(self, playerEntityID, curCount, interval):
		#不管是实际玩家，还是机器人打牌超时后，都会走AI逻辑
		# 如果是玩家，超时打牌次数太多，自动进入托管状态
		playerEntity = KBEngine.entities.get(playerEntityID)
		if playerEntity.playerType == RoomDef.PlayerType.Client \
			and playerEntity.curState != StateDef.Player.AutoPlayout:
			# 玩家打牌超时了
			playerEntity.playoutTimeoutCount += 1
			if playerEntity.playoutTimeoutCount >= RoomDef.AutoPlayoutTimeoutCount:
				playerEntity.curState = StateDef.Player.AutoPlayout

		from logic import PlayModule
		# 如果是第一个玩家出牌的话，这里肯定会给出有效牌
		cardsInfo = PlayModule.Instance().getPlayoutCards(playerEntityID)
		cardType = cardsInfo[0]
		playoutCards = cardsInfo[1]
		msg = []
		msg.append(MsgDef.CLIENT2CELL_ROOM_MSG)
		msg.append(RoomDef.SUBMSG_PALYOUT_CARD)
		msg.append(cardType)
		msg.append(len(playoutCards))
		msg.extend(playoutCards)
		self.playoutCard(playerEntityID, msg)

	def playoutCard(self, playerEntityID, args):
		playerEntity = KBEngine.entities.get(playerEntityID)
		if self.isCurPlayerOp(playerEntityID) == False \
			or (playerEntity.curState != StateDef.Player.FirstPlayout and playerEntity.curState != StateDef.Player.FollowPlayout):
			return

		IKernel.Instance().delHeartbeat(playerEntity.id, "RoomModule.HB_playoutTimeout")

		nextEntityIDAndPos = self.getNextOpPlayerEntityIDAndPos(playerEntity.id)
		nextEntityID = nextEntityIDAndPos[0]
		nextEntity = KBEngine.entities.get(nextEntityID)
		nextPos = nextEntityIDAndPos[1]

		roomEntity = KBEngine.entities.get(playerEntity.roomEntityID)

		playoutCardType = args[2]
		playoutCardNum = args[3]
		if playoutCardType <= CardDef.PlayoutCardType.Invalid \
			or playoutCardType >= CardDef.PlayoutCardType.Max \
			or playoutCardNum < 1 \
			or playoutCardNum != len(args) - 4:# len(args)-4 是因为已经用了4个参数的长度了
			# 出牌无效，说明不要上一个玩家出的牌
			playerEntity.curState = StateDef.Player.CantAffordWait

			followPlayoutEntiityID = None
			cantAffordNum = 0
			for i in range(0, RoomDef.OneRoomMaxPlayerNum):
				loopPlayerEntityID = roomEntity.allPlayers[i]
				loopPlayerEntity = KBEngine.entities.get(loopPlayerEntityID)
				if loopPlayerEntity.curState == StateDef.Player.CantAffordWait:
					cantAffordNum = cantAffordNum + 1
				else:
					followPlayoutEntiityID = loopPlayerEntity

			# 有两个人都要不起牌的话，就重新开始一圈的打牌了
			if cantAffordNum == RoomDef.OneRoomMaxPlayerNum - 1:
				for i in range(0, RoomDef.OneRoomMaxPlayerNum):
					loopPlayerEntityID = roomEntity.allPlayers[i]
					loopPlayerEntity = KBEngine.entities.get(loopPlayerEntityID)
					if loopPlayerEntity.id == followPlayoutEntiityID:
						loopPlayerEntity.curState = StateDef.Player.FirstPlayout
					else:
						loopPlayerEntity.curState = StateDef.Player.WaitPlayout
				return

			nextEntity.curState = StateDef.Player.FollowPlayout
			roomEntity.curOpCardPlayerPos = nextPos
			return

		playoutCards = []
		for i in range(4, len(args)):
			playoutCards.append(args[i])

		from logic import PlayModule
		if PlayModule.Instance().canPlayout(playerEntityID, playoutCardType, playoutCards) == False:
			return

		from FUSE_FIELD import FUSE_FIELD
		fmtCards = FUSE_FIELD()

		for card in playoutCards:
			fmtCards[card] = 1
			playerEntity.handCards.pop(card)

		playerEntity.curPlayoutCards.update(fmtCards)

		roomEntity.lastPlayoutCardType = playoutCardType
		roomEntity.lastPlayoutCards.update(fmtCards)

		if len(playerEntity.handCards) == 0:
			playerEntity.curState = StateDef.Player.Win
			return

		playerEntity.curState = StateDef.Player.AfterPlayoutWait

		nextEntity = KBEngine.entities.get(nextEntityID)
		nextEntity.curState = StateDef.Player.FollowPlayout
		roomEntity.curOpCardPlayerPos = nextPos

	def handWin(self, roomEntityID):
		pass